# -*- coding: utf-8 -*-

from functools import partial
from decimal import Decimal

from common.utils import math_helper
# from common.lottery.cyclical.lucky_farm.model import BET_TYPE
from common.lottery.cyclical.lucky_farm.order import *
from common.lottery.cyclical.ssc.order import (
    ssc_calc_win_price_decorator,
    ssc_calc_total_price_decorator,
    ssc_valid_number_decorator,
    ssc_generate_win_func_decorator
)
# RATE_CONFIG = {         # base on UNIT==2
#     BET_TYPE.ONE_SINGLE: 10,
#     BET_TYPE.TWO_SINGLE: 100,
#     BET_TYPE.THREE_SINGLE: 1000,
#     BET_TYPE.FIVE_SINGLE: 100000,
#     BET_TYPE.TWO_COMBINE: 50,
#     BET_TYPE.THREE_GROUP_SINGLE: 320,
#     BET_TYPE.THREE_GROUP_MULTI: 320,
#     BET_TYPE.THREE_GROUP_SIX: 160,
#     BET_TYPE.FIVE_ALL: [20000, 200, 20],    # 全部，前后三，前后二
#     BET_TYPE.TWO_BSOE: 4,
#     BET_TYPE.TWO_SUM: 100,
#     BET_TYPE.CHOSEN_ONE: 10,
# }

UNIT = 2            # 彩票单价


# # @ssc_valid_number_decorator
# def valid_number(bet_type, number):
#     '''同一位之间用','隔开
#        不同位之间用'|'隔开
#        与顺序无关的选项，使用','隔开
#     '''
#     positions = number.split('|')
#     nums = []
#     for position in positions:
#         if not position:
#             continue
#         ds = position.split(',')
#         for d in ds:
#             if bet_type == BET_TYPE.TWO_SUM:
#                 assert 0 <= int(d) <= 18, 'two sum name range error'
#             elif bet_type == BET_TYPE.TWO_BSOE:
#                 # big: 大, small: 小, odd: 单, even: 双
#                 assert d in ('b', 's', 'o', 'e'), 'number format wrong'
#             else:
#                 assert 0 <= int(d) <= 9, 'number range error'
#         nums.append(ds)
#     if bet_type == BET_TYPE.TWO_BSOE:
#         assert len(positions) == 2, 'bsoe number format error'
#     elif bet_type == BET_TYPE.ONE_SINGLE:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'one single number format error'
#         assert 1 <= len(nums[0]) <= 10, 'one single number format error'
#     elif bet_type == BET_TYPE.TWO_SINGLE:
#         assert len(positions) == 2, 'two single number format error'
#     elif bet_type == BET_TYPE.THREE_SINGLE:
#         assert len(positions) == 3, 'three single number format error'
#     elif bet_type == BET_TYPE.FIVE_SINGLE:
#         assert len(positions) == 5, 'five single number format error'
#     elif bet_type == BET_TYPE.TWO_COMBINE:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'two combine number format error'
#         assert len(set(nums[0])) == len(nums[0]), 'two combine number no dup'
#     elif bet_type == BET_TYPE.THREE_GROUP_SINGLE:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'three group single number format error'
#         assert len(nums[0]) == 3,\
#             'three group single number length should be 3'
#         assert len(set(nums[0])) == 2, 'three group single should has 2 equal'
#     elif bet_type == BET_TYPE.THREE_GROUP_MULTI:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'three group multi number format error'
#         assert len(nums[0]) >= 2, 'three group multi number should at least 2'
#         assert len(set(nums[0])) == len(nums[0]),\
#             'three group multi number dup'
#     elif bet_type == BET_TYPE.THREE_GROUP_SIX:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'three group six number format error'
#         assert len(nums[0]) >= 3, 'three group six number at least 3'
#         assert len(set(nums[0])) == len(nums[0]), 'three group six number dup'
#     elif bet_type == BET_TYPE.FIVE_ALL:
#         assert len(positions) == 5, 'five all number format wrong'
#     elif bet_type == BET_TYPE.TWO_SUM:
#         assert len(positions) == 1 and len(nums) == 1,\
#             'two sum number need no `|`'
#         assert 19 >= len(nums[0]) >= 1, 'two sum number format wrong'
#     elif bet_type == BET_TYPE.CHOSEN_ONE:
#         assert len(positions) == 5 and len(nums) >= 1, 'format wrong'
#     else:
#         assert False, 'bet_type invalid'


# @ssc_calc_total_price_decorator
# def calc_total_price(bet_type, number, times=1, unit=UNIT):
#     '''根据不同的竞猜方式计算所需总价
#     '''
#     positions = number.split('|')
#     nums = []
#     for position in positions:
#         if not position:
#             continue
#         ds = position.split(',')
#         nums.append(ds)
#     if bet_type in (BET_TYPE.ONE_SINGLE, BET_TYPE.TWO_SINGLE,
#                     BET_TYPE.THREE_SINGLE, BET_TYPE.FIVE_SINGLE,
#                     BET_TYPE.FIVE_ALL, BET_TYPE.TWO_BSOE,
#                     BET_TYPE.CHOSEN_ONE):
#         # 这几种都是用逗号直接分割，总注数等于各串长度之乘积
#         price = 0 if bet_type == BET_TYPE.CHOSEN_ONE else 1
#         for num in nums:
#             if bet_type == BET_TYPE.CHOSEN_ONE:  # 定位胆的注数是和值
#                 price += len(num)
#             else:
#                 price *= len(num)
#         return price * times * unit
#     elif bet_type == BET_TYPE.TWO_COMBINE:
#         # 两星组选，一个字符串，个位十位所有数字的组合，结果为C(n, 2)
#         n = len(nums[0])
#         return math_helper.c(n, 2) * times * unit
#     elif bet_type == BET_TYPE.THREE_GROUP_SIX:
#         # 组选六，类似，也是一个组合
#         n = len(nums[0])
#         return math_helper.c(n, 3) * times * unit
#     elif bet_type == BET_TYPE.THREE_GROUP_SINGLE:
#         # 组三单选，固定是一注
#         return times * unit
#     elif bet_type == BET_TYPE.THREE_GROUP_MULTI:
#         # 组三复式，先任选两个，其中有一个要出现两次，所以是C(n, 2) * 2 = A(n, 2)
#         n = len(nums[0])
#         return math_helper.a(n, 2) * times * unit
#     elif bet_type == BET_TYPE.TWO_SUM:
#         # 二星和值，这个对于每个数字，出现的概率是固定的
#         count = 0
#         for num in nums[0]:
#             n = int(num)
#             if n < 10:
#                 count += (n + 1)
#             else:
#                 count += (19 - n)
#         return count * times * unit
#     else:
#         assert False, 'bet_type %s invalid' % bet_type


# @ssc_generate_win_func_decorator
# def generate_win_func(number):
#     '''根据开奖结果生成根据押注方式对应的中奖函数，避免重复计算
#     '''
#     result = {}

#     def n_single(n, x):
#         positions = x.split('|')
#         is_in = True
#         for i, v in enumerate(number[-n:]):
#             if v not in positions[i]:
#                 is_in = False
#                 break
#         return 1 if is_in else 0
#     result[BET_TYPE.ONE_SINGLE] = partial(n_single, 1)
#     result[BET_TYPE.TWO_SINGLE] = partial(n_single, 2)
#     result[BET_TYPE.THREE_SINGLE] = partial(n_single, 3)
#     result[BET_TYPE.FIVE_SINGLE] = partial(n_single, 5)

#     def chosen_one(x):
#         xs = x.split('|')
#         r = 0
#         for i, v in enumerate(xs):
#             hit = number[i]
#             if hit in v:
#                 r += 1
#         return r
#     result[BET_TYPE.CHOSEN_ONE] = chosen_one

#     def n_combine(n, x):
#         '''如果有重复数字视为失败
#         '''
#         nums = x.split(',')
#         return 1 if len(set(nums) & set(number[-n:])) == n else 0
#     result[BET_TYPE.TWO_COMBINE] = partial(n_combine, 2)
#     result[BET_TYPE.THREE_GROUP_SIX] = partial(n_combine, 3)

#     last_3_set = set(number[-3:])
#     is_three_group = len(last_3_set) == 2

#     def three_group_single(x):
#         x = ''.join(x.split(','))
#         if not is_three_group:
#             return 0
#         if sorted(number[-3:]) == sorted(x):
#             return 1
#         return 0

#     def three_group_multi(x):
#         nums = x.split(',')
#         if not is_three_group:
#             return 0
#         is_all_in = True
#         for k in last_3_set:
#             if k not in nums:
#                 is_all_in = False
#                 break
#         return 1 if is_all_in else 0
#     result[BET_TYPE.THREE_GROUP_SINGLE] = three_group_single
#     result[BET_TYPE.THREE_GROUP_MULTI] = three_group_multi

#     def five_all(x):
#         '''和其他不同，这里返回的是命中的序列，即全中、前后三、前后二,
#            没中的话，返回-1
#         '''
#         positions = x.split('|')
#         max_hits = 0
#         max_start = -1
#         hit_start = -1
#         hits = 0
#         for i, position in enumerate(positions):
#             nums = position.split(',')
#             if number[i] in nums:
#                 hits += 1
#                 if hit_start == -1:
#                     hit_start = i
#             else:
#                 if hits > max_hits:
#                     max_hits = hits
#                     max_start = hit_start
#                 hit_start = -1
#                 hits = 0
#         if hits > max_hits:
#             max_hits = hits
#             max_start = hit_start

#         if max_hits == 5:
#             return 0
#         if max_hits >= 3 and max_start != 1:
#             return 1
#         if max_hits == 2 and (max_start == 0 or max_start == 3):
#             return 2
#         return -1
#     result[BET_TYPE.FIVE_ALL] = five_all

#     def two_bsoe(x):
#         last_2 = number[-2:]
#         desc = [set(), set()]
#         for i, letter in enumerate(last_2):
#             n = int(letter)
#             if n >= 5:
#                 desc[i].add('b')
#             else:
#                 desc[i].add('s')
#             if n % 2 == 0:
#                 desc[i].add('e')
#             else:
#                 desc[i].add('o')

#         guesses = x.split('|')
#         hit = 1
#         for i, guess in enumerate(guesses):
#             t = guess.split(',')
#             hit *= len(set(t) & desc[i])
#         return hit

#     result[BET_TYPE.TWO_BSOE] = two_bsoe

#     def two_sum(x):
#         guesses = x.split(',')
#         real_sum = str(int(number[-1]) + int(number[-2]))
#         return 1 if real_sum in guesses else 0
#     result[BET_TYPE.TWO_SUM] = two_sum

#     return result


# @ssc_calc_win_price_decorator
# def calc_win_price(funcs, bet_number, bet_type, times=1, unit=UNIT,
#                    rate_config=RATE_CONFIG):
#     '''根据开奖结果和押注方式/倍数，计算中奖金额
#     '''
#     func = funcs.get(bet_type)
#     base = 0
#     if bet_type == BET_TYPE.FIVE_ALL:
#         index = func(bet_number)
#         if index >= 0:
#             base = Decimal(rate_config.get(bet_type)[index])
#     else:
#         base = func(bet_number) * Decimal(rate_config.get(bet_type))

#     return Decimal(base) * Decimal(times) * Decimal(unit) / Decimal(UNIT)
